package main

import (
	"fmt"
	"os"
	"runtime"
	"time"
)

/*
 参考资料：
 https://www.codeleading.com/article/79713370338/

 TODO：
 [OK]SHA-512破解
 [OK]密码支持6位纯数字
 [OK]多线程运行
 [OK]进度展示
 进度记录
 支持命令行参数
  [OK]支持指定shadow文件
  [OK]支持指定并发度
  [OK]支持按CPU核数动态百分比并发度
  支持指定多个破解之间的串并方式
 多机协同
  参数支持指定运行模式（worker、main）
  任务包的规划
  网络交互
 密码支持6~12位数字、大小写字母、常见英文符号
 密码复杂度控制
 参数支持指定密码复杂度
 自动升级
*/

func main() {
	fmt.Println("shadow crack tool v0.1 yjt 20250906")

	// 获取系统逻辑CPU数量
	numCPU := runtime.NumCPU()
	fmt.Println("系统逻辑CPU数量:", numCPU)

	para := ParseCmdPara()
	shadowFile := para.ShadowFile
	concurrency := para.Concurrency
	isParallel := para.IsParallel
	runMode := para.RunMode
	workers := para.Workers
	template := para.Template

	if exists, _ := IsFile(shadowFile); !exists {
		fmt.Printf("shadow文件<%s>打开失败\n", shadowFile)
		return
	}

	if concurrency < 0 {
		concurrency = -concurrency * 100 / numCPU
	}
	if concurrency < 1 {
		concurrency = 1
	}
	if concurrency > numCPU {
		concurrency = numCPU
	}

	// TODO 解析复杂度表达式

	// TODO 展示复杂度的描述
	fmt.Printf("破解文件<%s>，并发数<%d>，是否并行<%v>，运行模式(m为主控、w为执行端)<%s>，执行端列表<%s>，密码模板<%s>\n",
		shadowFile, concurrency, isParallel, runMode, workers, template)

	// TODO 如果不是主控端，就不用执行主控流程了，直接监听端口等待任务即可
	if runMode == "w" {
		go listenPort()
	}

	if runMode == "m" {
		// 打开shadow文件
		content, err := os.ReadFile(shadowFile)
		if err != nil {
			fmt.Printf("打开shadow文件出错：%v\n", err)
			return
		}
		str := string(content)

		// 按行加载其中的内容，并提取出salt和hashed部分
		users := ParseShadowContent(str)
		fmt.Printf("shadow文件解析完成，加载%v个用户的信息\n", len(users))

		// 循环，按规则生成密码，开协程调用以上函数计算hashed，判断是否一致，一致则打印到屏幕上并发出结束信号
		startTime := time.Now()
		for _, oneUser := range users {
			user := oneUser.User
			passStr := oneUser.PassStr
			salt := oneUser.Salt
			fmt.Printf("开始破解用户%s的密码\n", user)
			// 按照复杂度的规则重建此段密码生成逻辑
			oneTask := NewGuessTask(concurrency, template, salt, passStr)
			go oneTask.Deal()
			for !oneTask.IsFinished() {
				time.Sleep(100 * time.Millisecond)
			}
			// close(oneTask.TaskChan)
			if oneTask.Result != "" {
				fmt.Printf("用户%s的密码破解完成，耗时%v，密码为：%s\n", user, time.Since(startTime).String(), oneTask.Result)
			}
		}
	}

	// 收尾
}
